﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using CalcSharp.Core.General;

namespace CalcSharp.Core.Containers
{
    public enum SetStorageType
    {
        mDouble, mFloat, mShort
    }

    /// <summary>
    /// Set Memory Data Class for serializaton
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public class SetData
    {
        public SetData()
        {
            this.desc = "";
            this.value = null;
        }
        public string desc;
        public ASet value;
    }

    /// <summary>
    /// Set Memory Manager class
    /// </summary>
    public class SetManager : IMemMan<SetData, ASet>
    {

        private SetStorageType mode;
        private Dictionary<string, ASet> Engine;

        public SetManager()
        {
            this.mode = SetStorageType.mFloat;
            this.Engine = new Dictionary<string, ASet>();
        }
        /// <summary>
        /// the number of elements in the memory
        /// </summary>
        public int Count
        {
            get { return this.Engine.Count; }
        }
        /// <summary>
        /// Clears thhe memory
        /// </summary>
        public void Clear()
        {
            this.Engine.Clear();
        }
        /// <summary>
        /// Tells wheather a variable name is used or not
        /// </summary>
        /// <param name="name">the variable name</param>
        /// <returns>true, if set, false if not</returns>
        public bool isset(string name)
        {
            return Engine.ContainsKey(name.ToLower());
        }
        /// <summary>
        /// delets a variable
        /// </summary>
        /// <param name="name">the variable name</param>
        public void unset(string name)
        {
            string test = Regex.Replace(name, Patterns.FloatArray, "-ok-");
            if (test != "-ok-") throw new CSException("Incorrect variable name: " + name);
            Engine.Remove(name.ToLower());
        }
        /// <summary>
        /// Adds a SetData item to the memory
        /// </summary>
        /// <param name="item">The item to be added</param>
        /// <returns>the number of elements in the memory</returns>
        public int Add(SetData item)
        {
            if (Engine.ContainsKey(item.desc)) Engine[item.desc] = item.value;
            else Engine.Add(item.desc, item.value);
            return Engine.Count;
        }
        /// <summary>
        /// Gets the set variable names
        /// </summary>
        public string[] keys
        {
            get
            {
                string[] rets = new string[this.Engine.Keys.Count];
                this.Engine.Keys.CopyTo(rets, 0);
                return rets;
            }
        }

        /// <summary>
        /// Packs a single variable for serializazion
        /// </summary>
        /// <param name="index">the variable's name</param>
        /// <returns>the packed variable</returns>
        public SetData PackSingle(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException("Name can't be null");
            name = name.ToLower();
            SetData ret = new SetData();
            ret.value = Engine[name];
            ret.desc = name;
            return ret;
        }

        /// <summary>
        /// Gets or sets a set value based on a variable name
        /// </summary>
        /// <param name="name">The variable name</param>
        /// <returns>The set which is stored under the name</returns>
        public ASet this[string name]
        {
            get
            {
                name = name.ToLower(CultureInfo.CurrentCulture);
                string test = Regex.Replace(name, Patterns.FloatArray, "-ok-");
                if (test != "-ok-") throw new CSException("Incorrect variable name!");
                ASet val = new FloatSet();
                if (this.Engine.ContainsKey(name)) val = Engine[name];
                return val;
            }
            set
            {
                name = name.ToLower(CultureInfo.CurrentCulture);
                string test = Regex.Replace(name, Patterns.FloatArray, "-ok-");
                if (test != "-ok-") throw new CSException("Incorrect variable name: " + name);
                if (this.Engine.ContainsKey(name)) this.Engine[name] = value;
                else
                {
                    this.Engine.Add(name, value);
                }
            }
        }

        public SetStorageType StorageMode
        {
            get { return this.mode; }
            set
            {
                if (this.mode != value)
                {
                    this.Engine.Clear();
                    this.mode = value;
                }
            }
        }
    }
}